#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <memory>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/wait.h>
#include <pthread.h>
#include "logger.hpp"
#include "Common.hpp"
#include "InetAddr.hpp"

const static int defaultfd = -1;
const static int backlock = 5;

class server
{
private:
    void HanderIO(int sockfd, InetAddr &client)
    {
        char buffer[1024];
        while (true)
        {
            buffer[0] = 0;
            ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
            if (n > 0)
            {
                buffer[n] = 0;
                std::string message = "server to say:";
                message += buffer;
                LOG(LogLevel::DEBUG) << client.ToString() << " say: " << buffer;
                ssize_t m = write(sockfd, message.c_str(), message.size());
            }
            else if (n == 0)
            {
                LOG(LogLevel::INFO) << "client "
                                    << client.ToString() << " quit, me too, close fd: " << sockfd;
                break;
            }
            else
            {
                LOG(LogLevel::WARNING) << "read client "
                                       << client.ToString() << " error, sockfd : " << sockfd;
                break;
            }
        }
        close(sockfd);
    }

public:
    server(uint16_t port)
        : _listenfd(defaultfd), _port(port)
    {
    }
    void init()
    {
        _listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listenfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket创建失败";
            exit(SOCK_CREATE_ERR);
        }
        LOG(LogLevel::INFO) << "socket创建成功 listenfd:" << _listenfd;
        InetAddr local(_port);
        if (bind(_listenfd, local.Addr(), local.len()) != 0)
        {
            LOG(LogLevel::FATAL) << "bind失败" << _listenfd;
            exit(SOCK_BIND_ERRO);
        }
        LOG(LogLevel::INFO) << "bind成功";
        if (listen(_listenfd, backlock) != 0)
        {
            LOG(LogLevel::FATAL) << "listen失败";
            exit(SOCK_LISTEN_ERRO);
        }
        LOG(LogLevel::INFO) << "listen成功";
    }
    static void *Routine(void *args)
    {
        ThreadData*td=static_cast<ThreadData*>(args);
        pthread_detach(pthread_self());
        td->_self->HanderIO(td->_sockfd,td->_addr);
        delete td;
        return nullptr;
    }
    class ThreadData
    {
    public:
        ThreadData(int sockfd, server *self, const InetAddr &addr)
            : _sockfd(sockfd), _self(self), _addr(addr)
        {
        }
    public:
        int _sockfd;
        server *_self;
        InetAddr _addr;
    };
    void start()
    {
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listenfd, (struct sockaddr *)&peer, &len);
            if (sockfd < 0)
            {
                LOG(LogLevel::WARNING) << "获取链接失败";
                continue;
            }
            LOG(LogLevel::WARNING) << "获取链接成功";
            InetAddr clientaddr(peer);
            // 单进程版本
            // HanderIO(sockfd, clientaddr);

            // 多进程版本
            // pid_t id = fork();
            // if (id < 0)
            // {
            //     LOG(LogLevel::FATAL) << "资源不足，fork失败";
            //     exit(SOCK_FORK_ERRO);
            // }
            // else if (id == 0)
            // {
            //     // 子进程
            //     close(_listenfd);
            //     if (fork() > 0)
            //         exit(OK);
            //     HanderIO(sockfd,clientaddr);
            //     exit(OK);
            // }
            // else
            // {
            //     // 父进程
            //     close(sockfd);
            //     pid_t rid=waitpid(id,nullptr,0);
            //     (void)rid;
            // }

            // 多线程版本
            pthread_t tid;
            ThreadData*td=new ThreadData(sockfd,this,clientaddr);
            pthread_create(&tid, nullptr, Routine, (void*)td);
        }
    }
    ~server() {}

private:
    int _listenfd;
    uint16_t _port;
};